﻿/**
<code>
  <author name="Zealic" email="zealic(at)gmail.com" type="Creator"/>
</code>
**/
using System;


namespace Zealib.Extensions
{
    /// <summary>
    /// Extensions for <seealso cref="System.Decimal"/> class.
    /// </summary>
    public static class DecimalExtensions
    {
        /// <summary>
        /// Returns the specified decimal value as an array of bytes.
        /// </summary>
        /// <param name="self">The decimal to convert.</param>
        /// <returns>An array of bytes with length 8.</returns>
        public static byte[] GetBytes(this decimal self)
        {
            int[] values = decimal.GetBits(self);
            byte[] lo = BitConverter.GetBytes(values[0]);
            byte[] mi = BitConverter.GetBytes(values[1]);
            byte[] hi = BitConverter.GetBytes(values[2]);
            byte[] flags = BitConverter.GetBytes(values[3]);
            byte[] buffer = new byte[16];
            for (int i = 0; i < lo.Length; i++)
            {
                buffer[i] = lo[i];
            }
            for (int i = 0; i < mi.Length; i++)
            {
                buffer[i + 4] = mi[i];
            }
            for (int i = 0; i < hi.Length; i++)
            {
                buffer[i + 8] = hi[i];
            }
            for (int i = 0; i < flags.Length; i++)
            {
                buffer[i + 12] = flags[i];
            }
            return buffer;
        }

        /// <summary>
        /// Returns a decimal converted from four bytes at a specified position in a byte array.
        /// </summary>
        /// <param name="value">An array of bytes.</param>
        /// <param name="startIndex">The starting position within value.</param>
        /// <returns>A decimal formed by four bytes beginning at <paramref name="startIndex"/>.</returns>
        public static decimal ToDecimal(byte[] value, int startIndex)
        {
            int lo = ((value[startIndex] | (value[startIndex + 1] << 8)) | (value[startIndex + 2] << 16)) | (value[startIndex + 3] << 24);
            int mid = ((value[startIndex + 4] | (value[startIndex + 5] << 8)) | (value[startIndex + 6] << 16)) | (value[startIndex + 7] << 24);
            int hi = ((value[startIndex + 8] | (value[startIndex + 9] << 8)) | (value[startIndex + 10] << 16)) | (value[startIndex + 11] << 24);
            int flags = ((value[startIndex + 12] | (value[startIndex + 13] << 8)) | (value[startIndex + 14] << 16)) | (value[startIndex + 15] << 24);
            try
            {
                return new decimal(new int[4] { lo, mid, hi, flags });
            }
            catch (ArgumentException e)
            {
                throw new ArgumentException("Invalid value!", e);
            }
        }

    }
}
